/*!
 * template.js v0.7.1 (https://github.com/yanhaijing/template.js)
 * API https://github.com/yanhaijing/template.js/blob/master/doc/api.md
 * Copyright 2015 yanhaijing. All Rights Reserved
 * Licensed under MIT (https://github.com/yanhaijing/template.js/blob/master/MIT-LICENSE.txt)
 */
/* eslint-disable */
(function (root, factory) {
	var template = factory(root);
	if (typeof define === "function" && define.amd) {
		// AMD
		define("template", function () {
			return template;
		});
	} else if (typeof exports === "object") {
		// Node.js
		module.exports = template;
	} else {
		// Browser globals
		var _template = root.template;

		template.noConflict = function () {
			if (root.template === template) {
				root.template = _template;
			}

			return template;
		};
		root.template = template;
	}
})(this, function (root) {
	"use strict";
	var o = {
		sTag: "<%", //开始标签
		eTag: "%>", //结束标签
		compress: false, //是否压缩html
		escape: true, //默认输出是否进行HTML转义
		error: function (e) {}, //错误回调
	};
	var functionMap = {}; //内部函数对象
	//修饰器前缀
	var modifierMap = {
		"": function (param) {
			return nothing(param);
		},
		h: function (param) {
			return encodeHTML(param);
		},
		u: function (param) {
			return encodeURI(param);
		},
	};

	var toString = {}.toString;
	var slice = [].slice;
	function type(x) {
		if (x === null) {
			return "null";
		}

		var t = typeof x;

		if (t !== "object") {
			return t;
		}

		var c = toString.call(x).slice(8, -1).toLowerCase();
		if (c !== "object") {
			return c;
		}

		if (x.constructor == Object) {
			return c;
		}

		return "unknown";
	}

	function isObject(obj) {
		return type(obj) === "object";
	}
	function isFunction(fn) {
		return type(fn) === "function";
	}
	function isString(str) {
		return type(str) === "string";
	}
	function extend() {
		var target = arguments[0] || {};
		var arrs = slice.call(arguments, 1);
		var len = arrs.length;

		for (var i = 0; i < len; i++) {
			var arr = arrs[i];
			for (var name in arr) {
				target[name] = arr[name];
			}
		}
		return target;
	}
	function clone() {
		var args = slice.call(arguments);
		return extend.apply(null, [{}].concat(args));
	}
	function nothing(param) {
		return param;
	}
	function encodeHTML(source) {
		return String(source)
			.replace(/&/g, "&amp;")
			.replace(/</g, "&lt;")
			.replace(/>/g, "&gt;")
			.replace(/\\/g, "&#92;")
			.replace(/"/g, "&quot;")
			.replace(/'/g, "&#39;");
	}
	function compress(html) {
		return html.replace(/\s+/g, " ").replace(/<!--[\w\W]*?-->/g, "");
	}
	function consoleAdapter(cmd, msg) {
		typeof console !== "undefined" && console[cmd] && console[cmd](msg);
	}
	function handelError(e) {
		var message = "template.js error\n\n";

		for (var key in e) {
			message += "<" + key + ">\n" + e[key] + "\n\n";
		}
		message += "<message>\n" + e.message + "\n\n";
		consoleAdapter("error", message);

		o.error(e);
		function error() {
			return "template.js error";
		}
		error.toString = function () {
			return '__code__ = "template.js error"';
		};
		return error;
	}
	function parse(tpl, opt) {
		var code = "";
		var sTag = opt.sTag;
		var eTag = opt.eTag;
		var escape = opt.escape;
		function parsehtml(line) {
			// 单双引号转义，换行符替换为空格
			line = line.replace(/('|")/g, "\\$1");
			var lineList = line.split("\n");
			var code = "";
			for (var i = 0; i < lineList.length; i++) {
				code +=
					';__code__ += ("' +
					lineList[i] +
					(i === lineList.length - 1 ? '")\n' : '\\n")\n');
			}
			return code;
		}
		function parsejs(line) {
			//var reg = /^(:?)(.*?)=(.*)$/;
			var reg = /^(?:=|(:.*?)=)(.*)$/;
			var html;
			var arr;
			var modifier;

			// = := :*=
			// :h=123 [':h=123', 'h', '123']
			if ((arr = reg.exec(line))) {
				html = arr[2]; // 输出
				if (Boolean(arr[1])) {
					// :开头
					modifier = arr[1].slice(1);
				} else {
					// = 开头
					modifier = escape ? "h" : "";
				}

				return (
					';__code__ += __modifierMap__["' +
					modifier +
					'"](typeof (' +
					html +
					') !== "undefined" ? (' +
					html +
					') : "")\n'
				);
			}

			//原生js
			return ";" + line + "\n";
		}

		var tokens = tpl.split(sTag);

		for (var i = 0, len = tokens.length; i < len; i++) {
			var token = tokens[i].split(eTag);

			if (token.length === 1) {
				code += parsehtml(token[0]);
			} else {
				code += parsejs(token[0], true);
				if (token[1]) {
					code += parsehtml(token[1]);
				}
			}
		}
		return code;
	}
	function compiler(tpl, opt) {
		var mainCode = parse(tpl, opt);

		var headerCode =
			"\n" +
			"    var html = (function (__data__, __modifierMap__) {\n" +
			'        var __str__ = "", __code__ = "";\n' +
			"        for(var key in __data__) {\n" +
			'            __str__+=("var " + key + "=__data__[\'" + key + "\'];");\n' +
			"        }\n" +
			"        eval(__str__);\n\n";

		var footerCode =
			"\n" +
			"        ;return __code__;\n" +
			"    }(__data__, __modifierMap__));\n" +
			"    return html;\n";

		var code = headerCode + mainCode + footerCode;
		code = code.replace(/[\r]/g, " "); // ie 7 8 会报错，不知道为什么
		try {
			var Render = new Function("__data__", "__modifierMap__", code);
			Render.toString = function () {
				return mainCode;
			};
			return Render;
		} catch (e) {
			e.temp =
				"function anonymous(__data__, __modifierMap__) {" + code + "}";
			throw e;
		}
	}
	function compile(tpl, opt) {
		opt = clone(o, opt);

		try {
			var Render = compiler(tpl, opt);
		} catch (e) {
			e.name = "CompileError";
			e.tpl = tpl;
			e.render = e.temp;
			delete e.temp;
			return handelError(e);
		}

		function render(data) {
			data = clone(functionMap, data);
			try {
				var html = Render(data, modifierMap);
				html = opt.compress ? compress(html) : html;
				return html;
			} catch (e) {
				e.name = "RenderError";
				e.tpl = tpl;
				e.render = Render.toString();
				return handelError(e)();
			}
		}

		render.toString = function () {
			return Render.toString();
		};
		return render;
	}
	function template(tpl, data) {
		if (typeof tpl !== "string") {
			return "";
		}

		var fn = compile(tpl);
		if (!isObject(data)) {
			return fn;
		}

		return fn(data);
	}

	template.config = function (option) {
		if (isObject(option)) {
			o = extend(o, option);
		}
		return clone(o);
	};

	template.registerFunction = function (name, fn) {
		if (!isString(name)) {
			return clone(functionMap);
		}
		if (!isFunction(fn)) {
			return functionMap[name];
		}

		return (functionMap[name] = fn);
	};
	template.unregisterFunction = function (name) {
		if (!isString(name)) {
			return false;
		}
		delete functionMap[name];
		return true;
	};

	template.registerModifier = function (name, fn) {
		if (!isString(name)) {
			return clone(modifierMap);
		}
		if (!isFunction(fn)) {
			return modifierMap[name];
		}

		return (modifierMap[name] = fn);
	};
	template.unregisterModifier = function (name) {
		if (!isString(name)) {
			return false;
		}
		delete modifierMap[name];
		return true;
	};

	template.__encodeHTML = encodeHTML;
	template.__compress = compress;
	template.__handelError = handelError;
	template.__compile = compile;
	template.version = "0.7.1";
	return template;
});
